package com.yonyou.pmclouds.workflow.service.rmiimpl;

import com.alibaba.dubbo.config.annotation.Service;
import com.yonyou.pmclouds.ApplicationConsts;
import com.yonyou.pmclouds.alterandvisa.entity.AlterAndVisaVO;
import com.yonyou.pmclouds.basecom.billstatus.BillStatusConst;
import com.yonyou.pmclouds.basecom.bp.template.SingleUpdateBpTemplate;
import com.yonyou.pmclouds.basecom.dao.BaseMapper;
import com.yonyou.pmclouds.basecom.entity.SuperVO;
import com.yonyou.pmclouds.basecom.exception.BusinessException;
import com.yonyou.pmclouds.basecom.runtime.RuntimeEnvironment;
import com.yonyou.pmclouds.basecom.util.BeanHelper;
import com.yonyou.pmclouds.basecom.util.CommonFieldConst;
import com.yonyou.pmclouds.externalservice.entity.FailedExternalRecordVO;
import com.yonyou.pmclouds.externalservice.rmiitf.FailedExternalRecordMaintain;
import com.yonyou.pmclouds.externalservice.rmiitf.FailedExternalRecordQuery;
import com.yonyou.pmclouds.messagenotice.entity.MessageNoticeVO;
import com.yonyou.pmclouds.messagenotice.rmiitf.MessageNoticeMaintain;
import com.yonyou.pmclouds.project.processor.ProjectBillUpdateForUpdate;
import com.yonyou.pmclouds.task.entity.TaskVO;
import com.yonyou.pmclouds.task.rmiitf.TaskRemoteService;
import com.yonyou.pmclouds.workflow.entity.*;
import com.yonyou.pmclouds.workflow.service.ProcessApprovalRecordService;
import com.yonyou.pmclouds.workflow.service.ProcessRuntimeService;
import com.yonyou.pmclouds.workflow.service.ProcessTaskService;
import com.yonyou.pmclouds.workflow.service.rmiitf.IFlowApprove;
import com.yonyou.pmclouds.workflow.service.rmiitf.IWorkFlowService;
import com.yonyou.pmclouds.workflow.util.ApprovalFlowExecutor;
import com.yonyou.pmclouds.workflow.util.ApprovalStatusEnum;
import com.yonyou.pmclouds.workflow.util.BillFieldNameFormatCoverUtil;
import com.yonyou.pmclouds.workflow.util.RejectFlowExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import yonyou.bpm.rest.request.RestVariable;
import yonyou.bpm.rest.request.task.TaskQueryParam;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service(version = ApplicationConsts.APPLICATION_VERSION, interfaceClass = IWorkFlowService.class, timeout = 10000)
public class WorkFlowServiceImp implements IWorkFlowService {

    @Autowired
    private IFlowApprove flowApprove;
    @Autowired
    private ProcessTaskService processTaskService;
    @Autowired
    private ProcessRuntimeService processRuntimeService;
    @Autowired
    private ProcessApprovalRecordService approvalRecordService;
    @Autowired
    private MessageNoticeMaintain noticeMaintain;
    @Autowired
    private ApprovalFlowExecutor approvalFlowExecutor;
    @Autowired
    private RejectFlowExecutor rejectFlowExecutor;
    @Autowired
    private TaskRemoteService taskRemoteService;
    @Autowired
    private FailedExternalRecordMaintain failedRecordMaintain;
    @Autowired
    private FailedExternalRecordQuery failedRecordQuery;
    @Autowired
    private ProjectBillUpdateForUpdate.ProjectBillForUpdateProcessorFactory<AlterAndVisaVO> billForUpdateProcessorFactory;

    @Override
    public Object approveInFlow(ApproveInfoParam approveInfoParam) throws BusinessException {
        approveInfoParam.setUserId(RuntimeEnvironment.getLoginUserId());
        approveInfoParam.setTenantId(RuntimeEnvironment.getTenantId());
        //一张单据每个接收人只会生成一条待办任务，所以如果接收人为null,则返回多条任务对象，这也是返回结果为数组的原因。
        TaskVO[] taskVOS = taskRemoteService.queryByPkBill(approveInfoParam.getPkBill(), null);
        List<String> pkTasks = new ArrayList<>();
        if (taskVOS != null && taskVOS.length > 0) {
            for (TaskVO taskVO : taskVOS) {
                pkTasks.add(taskVO.getPk_task());
            }
            approveInfoParam.setPkTasks(pkTasks);
        }
        //只是代表任务状态结束，而不是单据状态结束
        approvalFlowExecutor.addTask(approveInfoParam);

        // 将当前审批人的待办至为已完成，如果异步调用失败，再将该待办回滚
        taskRemoteService.finishTask(approveInfoParam.getPkBill(), null, BillStatusConst.COMMON_APPROVING_STATUS);
        return "success";
    }

    private ProcessTaskVO[] getLatestBillTask(String pkBill, String pkUser) throws BusinessException {
        TaskQueryParam taskQueryParam = getTaskQueryParam(pkBill, pkUser);
        return processTaskService.queryProcessTaskVOs(taskQueryParam);
    }

    private TaskQueryParam getTaskQueryParam(String pkBill, String pkUser) {
        TaskQueryParam taskQueryParam = new TaskQueryParam();
        taskQueryParam.setProcessInstanceBusinessKey(pkBill);
        taskQueryParam.setAssignee(pkUser);
        return taskQueryParam;
    }


    @Override
    public boolean approveByCallBack(String pkBill, String definitionKey) throws BusinessException {
        ProcessDefinitionVO definitionVO = this.getDefinitionByKey(definitionKey);

        if(definitionVO == null)
            throw new BusinessException("没有找到对应的流程定义信息");

        this.updateBillStatus(definitionVO.getBillType(), pkBill, BillStatusConst.COMMON_APPROVED_STATUS);

        boolean result = flowApprove.approve(pkBill, definitionKey, BillStatusConst.COMMON_APPROVED_STATUS);

        if (result) {
            // 流程审批完成，给制单人发送消息通知
            MessageNoticeVO noticeVO = new MessageNoticeVO();
            noticeVO.setRelateKey(pkBill);
            noticeVO.setRelateType(definitionVO.getBillType());
            noticeMaintain.insertMessageNotice(noticeVO);
        }
        return result;
    }

    @Override
    @Deprecated
    public SuperVO approveDirectly(String pkBill, String billType, byte billStatus) throws BusinessException {
        return flowApprove.approveByBillType(pkBill, billType, billStatus);
    }

    @Override
    public boolean reject(ApproveInfoParam approveInfoParam) throws BusinessException {
        approveInfoParam.setUserId(RuntimeEnvironment.getLoginUserId());
        approveInfoParam.setTenantId(RuntimeEnvironment.getTenantId());
        TaskVO[] taskVOS = taskRemoteService.queryByPkBill(approveInfoParam.getPkBill(), approveInfoParam.getUserId());
        List<String> pkTasks = new ArrayList<>();
        if (taskVOS != null && taskVOS.length > 0) {
            for (TaskVO taskVO : taskVOS) {
                pkTasks.add(taskVO.getPk_task());
            }
            approveInfoParam.setPkTasks(pkTasks);
        }
        rejectFlowExecutor.addTask(approveInfoParam);
        //将友工程的待办任务置为完成
        taskRemoteService.finishTask(approveInfoParam.getPkBill(), approveInfoParam.getUserId(), BillStatusConst.COMMON_REJECT_STATUS);

        this.updateBillStatus(approveInfoParam.getBillType(), approveInfoParam.getPkBill(), BillStatusConst.COMMON_REJECT_STATUS);
        return true;
    }

    @Override
    public SuperVO getBuziVOForWorkFlow(String pkBill, String billType) throws BusinessException {

        return flowApprove.getBuziVOForWorkFlow(pkBill, billType);
    }

    @Override
    public List<ProcessRunTimeVO> getApprovalRecord(String userId, String tenantId, String businessKey, String billType)
            throws BusinessException {
        List<ProcessRunTimeVO> runTimeVOList = approvalRecordService.getApprovalRecord(userId, tenantId, businessKey);

        if (runTimeVOList == null || runTimeVOList.size() <= 0) {
            return null;
        }

        // 单据状态为驳回状态时，删除掉最后一个审批节点，因为现在规定第一个节点不设置为制单人，驳回只会驳回到第一个环节点
        // 审批记录添加驳回再提交环节

        return rejectFilterAndFillSubmit(runTimeVOList, businessKey, billType);
    }

    private List<ProcessRunTimeVO> rejectFilterAndFillSubmit(List<ProcessRunTimeVO> runTimeVOList, String businessKey, String billType) throws BusinessException {
        SuperVO bizVo = this.getBuziVOForWorkFlow(businessKey, billType);
        if (bizVo != null) {
            byte billStatus = (byte) BeanHelper.getProperty(bizVo, BillFieldNameFormatCoverUtil.getBillStatusFieldName(bizVo));
            if (BillStatusConst.COMMON_REJECT_STATUS == billStatus) {
                runTimeVOList.remove(runTimeVOList.size() - 1);
            }
        } else {
            throw new BusinessException("查询对应单据为空");
        }

        List<ProcessRunTimeVO> newRunTimeList = new ArrayList<>(runTimeVOList);
        int countNum = 0;
        // 添加驳回再提交状态审批记录
        for (int i = 0; i < runTimeVOList.size(); i++) {
            if (ApprovalRecordVO.APPROVAL_STATUS_REJECT.equalsIgnoreCase(runTimeVOList.get(i).getApprovalStatus()) &&
                    i < (runTimeVOList.size() - 1)) {
                String approvalPersonCode = (String) BeanHelper.getProperty(bizVo, CommonFieldConst.CREATOR);
                String startTime = runTimeVOList.get(i).getApprovalRecordVOList().get(0).getEndTime();
                String endTime = runTimeVOList.get(i + 1).getStartTime();
                ProcessRunTimeVO runTimeVO = bulidRejectVO(approvalPersonCode, businessKey, startTime, endTime);
                newRunTimeList.add(i + 1 + countNum, runTimeVO);
                countNum++;
            }
        }
        return newRunTimeList;
    }

    private ProcessRunTimeVO bulidRejectVO(String approvalPersonCode, String businessKey, String startTime, String endTime) {
        ProcessRunTimeVO runTimeVO = new ProcessRunTimeVO();
        runTimeVO.setApprovalStatus(ApprovalRecordVO.APPROVAL_STATUS_SUBMIT);
        runTimeVO.setApprovalStatusDesc(ApprovalStatusEnum.getName(ApprovalRecordVO.APPROVAL_STATUS_SUBMIT));
        runTimeVO.setStartTime(startTime);
        runTimeVO.setAllApprovalPersonCode(approvalPersonCode);

        ApprovalRecordVO approvalRecordVO = new ApprovalRecordVO();
        approvalRecordVO.setApprovalPersonCode(approvalPersonCode);
        approvalRecordVO.setApprovalComment("提交了单据");
        approvalRecordVO.setApprovalNodeName("制单人");
        approvalRecordVO.setApprovalStatus(ApprovalRecordVO.APPROVAL_STATUS_SUBMIT);
        approvalRecordVO.setApprovalStatusDesc(ApprovalStatusEnum.getName(ApprovalRecordVO.APPROVAL_STATUS_SUBMIT));
        approvalRecordVO.setFinished(true);
        approvalRecordVO.setStartTime(startTime);
        approvalRecordVO.setEndTime(endTime);
        approvalRecordVO.setBusinessKey(businessKey);
        List<ApprovalRecordVO> approvalRecordVOList = new ArrayList<>();
        approvalRecordVOList.add(approvalRecordVO);
        runTimeVO.setApprovalRecordVOList(approvalRecordVOList);
        return runTimeVO;
    }

    @Override
    public boolean checkApprovePerm(String pkBill, String pkUser) throws BusinessException {

        ProcessTaskVO[] processTaskVOs = getLatestBillTask(pkBill, pkUser);

        if (ArrayUtils.isNotEmpty(processTaskVOs))
            return true;

        return false;
    }

    @Override
    public ProcessDefinitionVO getDefinitionByKey(String definitionKey) throws BusinessException {
        return flowApprove.getDefinitionByKey(definitionKey);
    }

    public List<RestVariable> getVariableList(SuperVO businessVO) throws BusinessException {
        return processRuntimeService.getVariableList(businessVO);
    }

    @Override
    public SuperVO deleteBill(String pkBill, String billType) throws BusinessException {
        return flowApprove.deleteBill(pkBill, billType);
    }

    @Override
    public void afterFlowStarted(StartFlowArgsVO startFlowArgsVO) throws BusinessException {
        String processKey = startFlowArgsVO.getProcessKey();
        String billType = startFlowArgsVO.getBillType();
        SuperVO businessVO = startFlowArgsVO.getBusinessVO();
        String billStatusField = BillFieldNameFormatCoverUtil.getBillStatusFieldName(businessVO);

        if(StringUtils.isEmpty(processKey)){
            // 单据未配置启用的审批流，单据状态直接置为审批通过
            BeanHelper.setProperty(businessVO, billStatusField, BillStatusConst.COMMON_APPROVED_STATUS);
            this.updateBillStatus(billType, String.valueOf(businessVO.pkFiledValue()), BillStatusConst.COMMON_APPROVED_STATUS);
            flowApprove.approveByBillType((String) businessVO.pkFiledValue(), billType, BillStatusConst.COMMON_APPROVED_STATUS);
        }else{
            // 首次提交或者驳回再提交，均将单据状态置为审批中
            BeanHelper.setProperty(businessVO, billStatusField, BillStatusConst.COMMON_APPROVING_STATUS);
            this.updateBillStatus(billType, String.valueOf(businessVO.pkFiledValue()), BillStatusConst.COMMON_APPROVING_STATUS);
        }

        // 检查失败记录表是否存在失败记录，存在则删除
        FailedExternalRecordVO recordVO = failedRecordQuery.queryByPkBill(businessVO.pkFiledValue().toString());
        if(recordVO != null){
            failedRecordMaintain.delete(recordVO);
        }
    }

    @Override
    public void updateBillStatus(String billType, String pkBill, byte billStatus) throws BusinessException {
        SuperVO newBusinessVO = flowApprove.getBuziVOForWorkFlow(pkBill, billType);
        if(newBusinessVO == null){
            throw new BusinessException("审批修改单据状态失败: billType = " + billType + ", pkBill = " + pkBill + ", billStatus = " + billStatus);
        }
        BaseMapper baseMapper = (BaseMapper) flowApprove.getBusinessMapper(billType);
        if(baseMapper == null){
            throw new BusinessException("该单据的服务类未配置Mapper，请检查该配置项");
        }

        String billStatusField = BillFieldNameFormatCoverUtil.getBillStatusFieldName(newBusinessVO);

        BeanHelper.setProperty(newBusinessVO, billStatusField, billStatus);

        SingleUpdateBpTemplate updateBpTemplate = new SingleUpdateBpTemplate(baseMapper, new String[]{billStatusField});
        updateBpTemplate.addAfterProcessor(billForUpdateProcessorFactory.getProcessor(billType));
        updateBpTemplate.update(newBusinessVO);
    }
}
